//----------------------------------------------------------------------------------------------------------------------
// Copyright (c) 2012 James Whitworth
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the \"Software\"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//----------------------------------------------------------------------------------------------------------------------

local file = vargv[0]
if (type(file) != "instance" || file.getclass() != File)
{
  throw "expected instance of class File"
}

file.namespace = "sqb"

file.header_includes.append("sqbind/sqbTypeInfo.h")

const kSetParamsCheckFunctionName = "SetParamsCheck"
const kInstanceTypeName = "InstanceType"
const kReturnTypeName = "ReturnType"
const kParameterTypeName = "ParameterType"

enum CallTypes
{
  kFunction,
  kClassFunction,
  kConstClassFunction,
}

//----------------------------------------------------------------------------------------------------------------------
local add_setparamscheck_body = function(setparamscheck, argument_count)
{
  setparamscheck.body.add_line("SQChar typemask[] =")
  setparamscheck.body.add_line("{")
  setparamscheck.body.add_line("  _SC('.'),")

  for (local i = 0; i != argument_count; ++i)
  {
    setparamscheck.body.add_line(
      "  _SC(%s::TypeInfo<typename %s::traits::RemoveQualifiers<%s%d>::kType>::kTypeMask),",
      file.namespace,
      file.namespace,
      kParameterTypeName, i)
  }

  setparamscheck.body.add_line("  _SC('\\0')")
  setparamscheck.body.add_line("};")
  setparamscheck.body.add_new_line()
  setparamscheck.body.add_line("return sq_setparamscheck(vm, %d, typemask);", argument_count + 1)
}

//----------------------------------------------------------------------------------------------------------------------
local add_setparamscheck_function = function(paramcheckhelper, argument_count, call_type)
{
  local setparamscheck = Function(kSetParamsCheckFunctionName, CodeGenerator.kInline | CodeGenerator.kStatic)
  setparamscheck.return_type = Parameter("SQRESULT")

  setparamscheck.parameters.append(Parameter("HSQUIRRELVM", "vm"))

  local function_pointer = Function("function", CodeGenerator.kPointer | CodeGenerator.kUnused)
  function_pointer.return_type = Parameter(kReturnTypeName, "", CodeGenerator.kTemplate)

  if (call_type == CallTypes.kClassFunction)
  {
    function_pointer.owner = Class(kInstanceTypeName, CodeGenerator.kTemplate)
  }
  else if (call_type == CallTypes.kConstClassFunction)
  {
    function_pointer.owner = Class(kInstanceTypeName, CodeGenerator.kTemplate)
    function_pointer.set_flags(CodeGenerator.kConst)
  }

  for (local i = 0; i != argument_count; ++i)
  {
    function_pointer.parameters.append(Parameter(format("%s%d", kParameterTypeName, i), "", CodeGenerator.kTemplate))
  }

  setparamscheck.parameters.append(function_pointer)

  add_setparamscheck_body(setparamscheck, argument_count)
  paramcheckhelper.public.functions.append(setparamscheck)
}

local paramcheckhelper = Class("ParamCheckHelper")

for (local i = 0; i != _OPTIONS["iterations"] + 1; ++i)
{
  // template<typename RT>
  // SQInteger kSetParamsCheckFunctionName(HSQUIRRELVM vm, RT (*function)())
  //
  add_setparamscheck_function(paramcheckhelper, i, CallTypes.kFunction)
  
  // template<typename kInstanceTypeName, typename RT>
  // SQInteger kSetParamsCheckFunctionName(HSQUIRRELVM vm, RT (kInstanceTypeName::*function)())
  //
  add_setparamscheck_function(paramcheckhelper, i, CallTypes.kClassFunction)

  // template<typename kInstanceTypeName, typename RT>
  // SQInteger kSetParamsCheckFunctionName(HSQUIRRELVM vm, RT (kInstanceTypeName::*function)())
  //
  add_setparamscheck_function(paramcheckhelper, i, CallTypes.kConstClassFunction)
}

file.contents.append(paramcheckhelper)